from typing import List, Dict, Optional, Tuple
import random
from datetime import datetime


class BattleSystem:
    def __init__(self):
        self._battle_log = []
        self._current_turn = 0
        self._battle_active = False
    
    def start_battle(self, team1: List, team2: List, arena_name: str = "Chang'An Arena") -> Dict:
        self._battle_log.clear()
        self._current_turn = 0
        self._battle_active = True
        
        for champion in team1 + team2:
            champion.reset_for_battle()
        
        self._log_event(f"Battle begins in {arena_name}!")
        self._log_event(f"Team 1: {', '.join([c.name for c in team1])}")
        self._log_event(f"Team 2: {', '.join([c.name for c in team2])}")
        
        return {
            "success": True,
            "message": f"Battle started in {arena_name}",
            "team1": [c.name for c in team1],
            "team2": [c.name for c in team2]
        }
    
    def execute_turn(self, team1: List, team2: List) -> Dict:
        if not self._battle_active:
            return {"success": False, "message": "No active battle"}
        
        self._current_turn += 1
        self._log_event(f"\\n Turn {self._current_turn}")
        
        all_champions = team1 + team2
        alive_champions = [c for c in all_champions if c.is_alive]
        
        if len(alive_champions) <= 1:
            return self._end_battle(team1, team2)
        
        turn_order = sorted(alive_champions, key=lambda c: c.speed, reverse=True)
        
        turn_results = []
        
        for champion in turn_order:
            if not champion.is_alive:
                continue
            
            self._apply_status_effects(champion)
            
            action = self._get_champion_action(champion, team1, team2)
            
            if action:
                result = self._execute_action(champion, action, team1, team2)
                turn_results.append(result)
        team1_alive = [c for c in team1 if c.is_alive]
        team2_alive = [c for c in team2 if c.is_alive]
        
        if not team1_alive or not team2_alive:
            return self._end_battle(team1, team2)
        
        return {
            "success": True,
            "turn": self._current_turn,
            "results": turn_results,
            "team1_alive": len(team1_alive),
            "team2_alive": len(team2_alive)
        }
    
    def _get_champion_action(self, champion, team1: List, team2: List) -> Optional[Dict]:
        if champion in team1:
            allies = [c for c in team1 if c.is_alive and c != champion]
            enemies = [c for c in team2 if c.is_alive]
        else:
            allies = [c for c in team2 if c.is_alive and c != champion]
            enemies = [c for c in team1 if c.is_alive]
        
        if not enemies:
            return None
        if random.random() < 0.7:
            target = random.choice(enemies)
            return {
                "type": "attack",
                "target": target,
                "ability": None
            }
        else:
            abilities = champion.get_abilities()
            if abilities and champion.mana >= 20:  
                ability = random.choice(abilities)
                target = random.choice(enemies) if random.random() < 0.8 else None
                return {
                    "type": "ability",
                    "target": target,
                    "ability": ability
                }
            else:
                target = random.choice(enemies)
                return {
                    "type": "attack",
                    "target": target,
                    "ability": None
                }
    
    def _execute_action(self, champion, action: Dict, team1: List, team2: List) -> Dict:
        if action["type"] == "attack":
            result = champion.attack_target(action["target"])
            self._log_event(result["message"])
            return result
        
        elif action["type"] == "ability":
            ability_name = action["ability"]
            target = action["target"]
            
            result = champion.use_ability(ability_name, target)
            if result["success"]:
                self._log_event(result["message"])
            else:
                self._log_event(f"{champion.name} failed to use {ability_name}: {result['message']}")
            
            return result
        
        return {"success": False, "message": "Unknown action type"}
    
    def _apply_status_effects(self, champion):
        for debuff in champion._debuffs[:]:
            if debuff["type"] in ["poison", "burn", "venom"]:
                damage = debuff.get("damage_per_turn", 0)
                if damage > 0:
                    actual_damage = champion.take_damage(damage, "true")
                    self._log_event(f"{champion.name} takes {actual_damage} damage from {debuff['type']}")
            
            debuff["duration"] -= 1
            if debuff["duration"] <= 0:
                champion._debuffs.remove(debuff)
        
        for buff in champion._buffs[:]:
            if buff["type"] == "guardian_spirits":
                healing = buff.get("healing_per_turn", 0)
                if healing > 0:
                    actual_healing = champion.heal(healing)
                    if actual_healing > 0:
                        self._log_event(f"{champion.name} is healed for {actual_healing} by guardian spirits")
            
            buff["duration"] -= 1
            if buff["duration"] <= 0:
                champion._buffs.remove(buff)
        
        if champion._is_stunned:
            champion._is_stunned = False
            self._log_event(f"{champion.name} is no longer stunned")
    
    def _end_battle(self, team1: List, team2: List) -> Dict:
        self._battle_active = False
        
        team1_alive = [c for c in team1 if c.is_alive]
        team2_alive = [c for c in team2 if c.is_alive]
        
        if team1_alive and not team2_alive:
            winner = "Team 1"
            survivors = [c.name for c in team1_alive]
        elif team2_alive and not team1_alive:
            winner = "Team 2"
            survivors = [c.name for c in team2_alive]
        else:
            winner = "Draw"
            survivors = []
        
        self._log_event(f"\\nBattle ended! Winner: {winner}")
        if survivors:
            self._log_event(f"Survivors: {', '.join(survivors)}")
        
        return {
            "success": True,
            "battle_ended": True,
            "winner": winner,
            "survivors": survivors,
            "total_turns": self._current_turn
        }
    
    def _log_event(self, message: str):
        timestamp = datetime.now().strftime("%H:%M:%S")
        log_entry = f"[{timestamp}] {message}"
        self._battle_log.append(log_entry)
        print(log_entry)
    
    def get_battle_log(self) -> List[str]:
        return self._battle_log.copy()
    
    def is_battle_active(self) -> bool:
        return self._battle_active
    
    def get_battle_status(self, team1: List, team2: List) -> Dict:
        team1_status = [c.get_status() for c in team1]
        team2_status = [c.get_status() for c in team2]
        
        return {
            "turn": self._current_turn,
            "battle_active": self._battle_active,
            "team1": team1_status,
            "team2": team2_status
        }